import {
  Children,
  cloneElement,
  createElement,
  CSSProperties,
  HTMLAttributes,
  isValidElement,
  useRef,
  useState,
  type FC,
} from 'react';
import classNames from 'classnames';
import { shapeDefaultProps } from './defaultProps';
import type { ShapeOptions } from './type';
import ShapeSide from './ShapeSide';
import { ShapeContextProvider, useShapeContext } from './ShapeContext';
import { useEffectOnce, useUpdateEffect } from 'react-use';

export interface ShapeProps extends ShapeOptions, HTMLAttributes<HTMLDivElement> {}

interface ShapeInterface extends FC<ShapeProps> {
  Side: typeof ShapeSide;
}

const Child: FC<ShapeProps> = (props) => {
  const { className, ui, cube, duration, behavior, change, style, children, forwardedRef, ...shapeProps } = props;

  const [animating, setAnimating] = useState(false);
  const [states, setStates] = useShapeContext();
  const [styles, setStyles] = useState<CSSProperties>();
  const [css, setCss] = useState<CSSProperties | undefined>(style);
  const ref = useRef<HTMLDivElement>(null);

  useEffectOnce(() => {
    setStates({ ...states, maxIndex: Children.count(children) - 1 });
  });

  useUpdateEffect(() => {
    const rect = ref.current?.getBoundingClientRect();
    let activeIndex;
    Children.forEach(children, (child, index) => {
      if (isValidElement(child) && child.props.active) {
        activeIndex = index;
      }
    });
    setAnimating(true);
    setStates({ ...states, width: rect?.width, height: rect?.height, activeIndex, animating: true });
    setTimeout(() => {
      setAnimating(false);
      setStates({ ...states, animating: false });
    }, duration);
  }, [change]);

  useUpdateEffect(() => {
    if (animating) {
      if (behavior === 'flip left') {
        setCss({ ...style, width: `${states.width}px`, height: `${states.height}px` });
        setStyles({
          transform: 'translateX(145px) translateZ(-145px) rotateY(90deg)',
          transitionDuration: `${duration}ms`,
        });
      }
    } else {
      setStyles(undefined);
      setCss(style);
    }
  }, [animating]);

  return createElement(
    'div',
    {
      ref: forwardedRef,
      className: classNames({ ui, cube, animating }, 'shape', className),
      style: css,
      ...shapeProps,
    },
    createElement(
      'div',
      { ref, className: 'sides', style: styles },
      Children.map(children, (child, index) => {
        if (isValidElement(child)) {
          return cloneElement(child, { ...child.props, index });
        }
      }),
    ),
  );
};

const Shape: ShapeInterface = (props) => {
  const { duration } = props;
  return (
    <ShapeContextProvider initialValue={{ animating: false, width: 0, height: 0, duration }}>
      <Child {...props} />
    </ShapeContextProvider>
  );
};

Shape.displayName = 'Shape';
Shape.defaultProps = shapeDefaultProps;

Shape.Side = ShapeSide;

export default Shape;

// animating     width: 290px; height: 467.219px;
//                transform: translateX(145px) translateZ(-145px) rotateY(90deg); transition-duration: 50000ms;
//    hidden      transform: rotateY(0deg); transition-duration: 50000ms;
//    animating    left: 0px; transform: rotateY(-90deg) translateZ(145px) translateX(-145px); transition-duration: 50000ms;
